package processing;

import gp.GP;
import gp.Node;

import java.io.IOException;
import java.util.ArrayList;

import processing.core.PApplet;
import processing.core.PFont;
import util.Reader;
import controlP5.ControlEvent;
import controlP5.ControlP5;
import controlP5.Textlabel;



public class ProcessingSketch extends PApplet {
	int width = 800;
	int height = 800;
	GP gp;
	ControlP5 cp5;
	int generation;
	int individuo;
	Textlabel generation_label;
	PFont fonte_nome_simbolo;
	ArrayList<IndCircle> indCircles;
	@SuppressWarnings("deprecation")
	public void setup(){
		cp5 = new ControlP5(this);
		size(width,height);
		background(205,191,172);
		fonte_nome_simbolo = createFont("Verdana", 12);
		this.gp = new GP();
		Reader reader = new Reader("./../test1");
		individuo = -1;
		try {
			reader.read(gp);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		generation = 0;
		generation_label =  cp5.addTextlabel("labelG")
				.setText("Generation 0")
				.setColorBackground(0)
				.setSize(100,19)
				.setPosition(width-100,0)
				.setColor(0);
		cp5.addButton("next").setValue(0).setPosition(100,0).setSize(100,19).setLabel("Next Generation");
		cp5.addButton("previous").setValue(0).setPosition(0,0).setSize(100,19).setLabel("Previous Generation");
		cp5.addButton("play").setValue(0).setPosition(200,0).setSize(100,19).setLabel("Play");
		cp5.addButton("pause").setValue(0).setPosition(300,0).setSize(100,19).setLabel("Pause").setSwitch(false);
		
		
	}
	
	public class IndCircle{
		double x0;
		double y0;
		float radius;
		
		public IndCircle(double x, double y, float radius){
			this.x0 = x;
			this.y0 = y;
			this.radius = radius;
		}
		
		public boolean isInside(float x, float y){
			double r = Math.sqrt( Math.pow( (x-x0), 2) + Math.pow((y-y0), 2) );
			return (r <=radius);
		}
	}
	
	public void controlEvent(ControlEvent theEvent){
	}
	
	public void change_generation(){
		individuo = -1;
		generation_label.setText("Generation " + Integer.toString(generation));
	}
	public void previous(int theValue){
		if(generation == 0){
			generation = 0;
		}else{
			generation = generation - 1;
		}
		change_generation();
	}
	public void next(int theValue){
		if(generation == (gp.generations.size()-1)){
			generation = generation;
		}else{
			generation = generation + 1;
		}
		change_generation();
	}
	public void play(int theValue){
		
	}
	public void pause(int theValue){
		
	}

	public void draw(){
		background(205,191,172);
		stroke(225,212,192);
		draw_circles(7);
		draw_generation(7,generation);
		if(individuo > 0){
			draw_tree(gp.generations.get(generation).individuos.get(individuo).get_root(), 400, 800, 1);
		}
	}

	public void draw_circles(int num_circles){
		strokeWeight(1.5f);
		fill(205,191,172);
		float step = (float)200/num_circles;
		ellipseMode(RADIUS);
		for(int i = num_circles-1; i > 0 ; i--){
			ellipse(200, 200, i*step, i*step);
		}
	}

	public void draw_generation(int num_circles, int indG){
		this.indCircles = new ArrayList<ProcessingSketch.IndCircle>();
		float step = (float)200/num_circles;
		fill(255,102,0);
		strokeWeight(1);
		for(int indI = 0 ; indI < gp.generations.get(indG).individuos.size(); indI++){
			double angle = gp.generations.get(indG).individuos.get(indI).calculate_angle(gp.alphabet);
			float height = gp.generations.get(indG).individuos.get(indI).get_height();
			double angle_nonTerminal = gp.generations.get(indG).individuos.get(indI).calculate_angle_nonTerminals(gp.alphabet);
			double height_nonTerminal = (height + 0.5f) * step;
			height = (height + 1)*step;
			double x = height * Math.cos(Math.toRadians(angle)) + 200;
			double y = height * Math.sin(Math.toRadians(angle)) + 200;
			
			if (angle_nonTerminal != -1) {
				double x_nonTerminal = height_nonTerminal * Math.cos(Math.toRadians(angle_nonTerminal)) + 200;
				double y_nonTerminal = height_nonTerminal * Math.sin(Math.toRadians(angle_nonTerminal)) + 200;
				
				stroke(0, 0, 0);
				line((float)x_nonTerminal, (float)y_nonTerminal, (float)x, (float)y);
				
				fill(102, 100, 0);
				stroke(225,212,192);
				ellipse((float)x_nonTerminal, (float)y_nonTerminal, 5, 5);
			}
			
			stroke(225,212,192);
			if(indI == individuo){
				fill(0, 0, 255);
				ellipse((float)x,(float)y, 5, 5);
			}
			else{
				fill(255, 102, 0);
				ellipse((float)x,(float)y, 5, 5);
			}
			this.indCircles.add(new IndCircle(x, y, (float)5 ));
			//System.out.println(angle);
		}
	}

	public void mousePressed(){
		for(int i = 0; i < this.indCircles.size(); i++){
			if(this.indCircles.get(i).isInside(mouseX, mouseY)){
				individuo = i;
			}
		}
	}
	
	public void draw_tree(Node node, float x_start, float x_end, float nivel){
		stroke(255,102,0);
		fill(255, 102, 0);
		float middle = (x_end + x_start)/2;
		ellipse(middle, nivel*30, 10,10);
		textFont(fonte_nome_simbolo);
		textAlign(CENTER, BASELINE);
		fill(0, 0, 0);
		text(node.symbol.getSimbolo(), middle, nivel*30-10);
		fill(255, 102, 0);
		if(node.has_left()){
			line(middle, nivel*30, (middle + x_start)/2, (nivel+1)*30);
			draw_tree(node.left, x_start, middle, nivel+1);
		}
		if(node.has_right()){
			line(middle, nivel*30, (middle + x_end)/2, (nivel+1)*30);
			draw_tree(node.right, middle, x_end, nivel+1);
		}
	}
}
